home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / fpu881 / src6.zoo / doprnt.c < prev    next >
C/C++ Source or Header  |  1991-09-24  |  18KB  |  743 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. /*
  19.  * minorly customized for gcc lib
  20.  *    ++jrb
  21.  * and for the sfp004
  22.  *      mjr++
  23.  */
  24. static unsigned long
  25.     __notanumber[2] = { 0x7fffffffL, 0xffffffffL }; /* ieee NAN */
  26. #define NAN  (*((double *)&__notanumber[0]))
  27.  
  28. #ifdef LIBC_SCCS
  29. static char sccsid[] = "@(#)doprnt.c    5.37 (Berkeley) 3/26/89";
  30. #endif /* LIBC_SCCS */
  31.  
  32. #include <sys/types.h>
  33. #include <stdarg.h>
  34. #include <stdio.h>
  35. #include <ctype.h>
  36. #include <string.h>
  37. #include <limits.h>
  38. #include    <math.h>
  39.  
  40. #ifndef __GNUC__    /* gcc lib has these typedefs in sys/types.h */
  41. typedef unsigned char u_char;
  42. typedef unsigned long u_long;
  43. #endif
  44.  
  45. /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
  46. #define    MAXEXP        308
  47. /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
  48. #define    MAXFRACT    39
  49.  
  50. #define    DEFPREC        6
  51.  
  52. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  53.  
  54. #define    PUTC(ch)     if( fputc(ch, fp) == EOF ) return EOF;
  55.  
  56. #define ARG(basetype) \
  57.     _ulong = flags&LONGINT ? va_arg(argp, long basetype) : \
  58.         flags&SHORTINT ? (short basetype)va_arg(argp, short) : \
  59.         va_arg(argp, int)
  60.  
  61. #define TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  62.  
  63. #define    todigit(c)    ((c) - '0')
  64. #define    tochar(n)    ((n) + '0')
  65.  
  66. #define    LONGINT        0x01        /* long integer */
  67. #define    LONGDBL        0x02        /* long double; unimplemented */
  68. #define    SHORTINT    0x04        /* short integer */
  69. #define    ALT        0x08        /* alternate form */
  70. #define    LADJUST        0x10        /* left adjustment */
  71. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  72. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  73.  
  74. #ifndef __NO_FLOAT__
  75. #define __FLOATS__ 1
  76. #endif
  77.  
  78. #ifdef __FLOATS__
  79. #ifdef __STDC__
  80. static char *exponent(char *, int, int);
  81. static char *round(double, int *, char *, char *, int, char *);
  82. static int  cvt(double, int, int, char *, int, char *, char *);
  83. #else
  84. static char *exponent();
  85. static char *round();
  86. static int  cvt();
  87. #endif
  88. #endif
  89.  
  90. #ifdef __GNUC__
  91. #define _ICONV(NUMBER, BASE, BUF)                 \
  92. {                                \
  93.     short i;                            \
  94.     if(NUMBER <= 65535L)                    \
  95.     {                                \
  96.     do                             \
  97.     {                            \
  98.         __asm__ volatile("  \
  99.          divu    %3,%2;  \
  100.          swap    %0;     \
  101.          movw    %0,%1;  \
  102.          clrw    %0;     \
  103.                 swap    %0"                    \
  104.              : "=d"((long)NUMBER), "=g"(i)            \
  105.          : "0"((long)NUMBER), "g"((short)BASE));    \
  106.         *--BUF = digs[i];                    \
  107.     } while(NUMBER);                    \
  108.     }                                \
  109.     else                            \
  110.     {                                \
  111.     extern unsigned long __udivsi3(); /* quot = d0, rem = d1 */     \
  112.     do                             \
  113.     {                            \
  114.         __asm__ volatile("        \
  115.          movl    %3,sp@-;      \
  116.          movl    %2,sp@-;      \
  117.          jsr    ___udivsi3;    \
  118.          movl    d0,%0;        \
  119.          movw    d1,%1;        \
  120.          addqw    #8,sp"                    \
  121.              : "=g"((long)NUMBER), "=g"(i)            \
  122.          : "0"((long)NUMBER), "g"((long)BASE)        \
  123.              : "d0", "d1", "a0", "a1");            \
  124.         *--BUF = digs[i];                    \
  125.     } while(NUMBER);                    \
  126.     }                                \
  127. }
  128. #endif /* __GNUC__ */
  129.  
  130.  
  131. int _doprnt(fp, fmt0, argp)
  132.     register FILE *fp;
  133.     u_char *fmt0;
  134.     va_list argp;
  135. {
  136.     register u_char *fmt;    /* format string */
  137.     register int ch;    /* character from fmt */
  138.     register int cnt;    /* return value accumulator */
  139.     register int n;        /* random handy integer */
  140.     register char *t;    /* buffer pointer */
  141.     double _double;        /* double precision arguments %[eEfgG] */
  142.     u_long _ulong;        /* integer arguments %[diouxX] */
  143.     short base;        /* base for [diouxX] conversion */
  144.     short dprec;        /* decimal precision in [diouxX] */
  145.     short fieldsz;        /* field size expanded by sign, etc */
  146.     short flags;        /* flags as above */
  147.     short fpprec;        /* `extra' floating precision in [eEfgG] */
  148.     short prec;        /* precision from format (%.3d), or -1 */
  149.     short realsz;        /* field size expanded by decimal precision */
  150.     short size;        /* size of converted field or string */
  151.     short width;        /* width from format (%8d), or 0 */
  152.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  153.     char softsign;        /* temporary negative sign for floats */
  154.     char *digs;        /* digits for [diouxX] conversion */
  155.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  156.  
  157.     fmt = fmt0;
  158.     digs = "0123456789abcdef";
  159.     for (cnt = 0;; ++fmt) {
  160.         if (!(ch = *fmt))
  161.             return (cnt);
  162.         if (ch != '%') {
  163.             PUTC(ch);
  164.             continue;
  165.         }
  166.         flags = 0; dprec = 0; fpprec = 0; width = 0;
  167.         prec = -1;
  168.         sign = '\0';
  169.  
  170. rflag:        switch (*++fmt) {
  171.         case ' ':
  172.             /*
  173.              * ``If the space and + flags both appear, the space
  174.              * flag will be ignored.''
  175.              *    -- ANSI X3J11
  176.              */
  177.             if (!sign)
  178.                 sign = ' ';
  179.             goto rflag;
  180.         case '#':
  181.             flags |= ALT;
  182.             goto rflag;
  183.         case '*':
  184.             /*
  185.              * ``A negative field width argument is taken as a
  186.              * - flag followed by a  positive field width.''
  187.              *    -- ANSI X3J11
  188.              * They don't exclude field widths read from args.
  189.              */
  190.             if ((width = (short)(va_arg(argp, int))) >= 0)
  191.                 goto rflag;
  192.             width = -width;
  193.             /* FALLTHROUGH */
  194.         case '-':
  195.             flags |= LADJUST;
  196.             goto rflag;
  197.         case '+':
  198.             sign = '+';
  199.             goto rflag;
  200.         case '.':
  201.             if (*++fmt == '*')
  202.                 n = va_arg(argp, int);
  203.             else {
  204.                 n = 0;
  205.                 while (isascii(*fmt) && isdigit(*fmt))
  206.                     n = TEN_MUL(n) + todigit(*fmt++);
  207.                 --fmt;
  208.             }
  209.             prec = n < 0 ? -1 : n;
  210.             goto rflag;
  211.         case '0':
  212.             /*
  213.              * ``Note that 0 is taken as a flag, not as the
  214.              * beginning of a field width.''
  215.              *    -- ANSI X3J11
  216.              */
  217.             flags |= ZEROPAD;
  218.             goto rflag;
  219.         case '1': case '2': case '3': case '4':
  220.         case '5': case '6': case '7': case '8': case '9':
  221.             n = 0;
  222.             do {
  223.                 n = TEN_MUL(n) + todigit(*fmt);
  224.             } while (isascii(*++fmt) && isdigit(*fmt));
  225.             width = n;
  226.             --fmt;
  227.             goto rflag;
  228.         case 'L':
  229.             flags |= LONGDBL;
  230.             goto rflag;
  231.         case 'h':
  232.             flags |= SHORTINT;
  233.             goto rflag;
  234.         case 'l':
  235.             flags |= LONGINT;
  236.             goto rflag;
  237.         case 'c':
  238.             *(t = buf) = va_arg(argp, int);
  239.             size = 1;
  240.             sign = '\0';
  241.             goto pforw;
  242.         case 'D':
  243.             flags |= LONGINT;
  244.             /*FALLTHROUGH*/
  245.         case 'd':
  246.         case 'i':
  247.             ARG(int);
  248.             if ((long)_ulong < 0) {
  249.                 _ulong = -_ulong;
  250.                 sign = '-';
  251.             }
  252.             base = 10;
  253.             goto number;
  254. #ifdef __FLOATS__
  255.         case 'e':
  256.         case 'E':
  257.         case 'f':
  258.         case 'g':
  259.         case 'G':
  260.             _double = va_arg(argp, double);
  261. /* mjr: check for NANs */
  262.             if(_double == NAN)    {
  263.                 t = strcpy(t, " Not A Number ");
  264.                 size = strlen(t);
  265.                 goto pforw;
  266.             }
  267.             /*
  268.              * don't do unrealistic precision; just pad it with
  269.              * zeroes later, so buffer size stays rational.
  270.              */
  271.             if (prec > MAXFRACT) {
  272.                 if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
  273.                     fpprec = prec - MAXFRACT;
  274.                 prec = MAXFRACT;
  275.             }
  276.             else if (prec == -1)
  277.                 prec = DEFPREC;
  278.             /*
  279.              * softsign avoids negative 0 if _double is < 0 and
  280.              * no significant digits will be shown
  281.              */
  282.             if (_double < 0) {
  283.                 softsign = '-';
  284.                 _double = -_double;
  285.             }
  286.             else
  287.                 softsign = 0;
  288. /* mjr: check for +-INFINITY */
  289.             if(_double == HUGE)    {
  290.             if(softsign == 0)
  291.                 t = strcpy(t, " Infinity ");
  292.             else
  293.                 t = strcpy(t, " -Infinity ");
  294.                 size = strlen(t);
  295.                 goto pforw;
  296.             }
  297.             /*
  298.              * cvt may have to round up past the "start" of the
  299.              * buffer, i.e. ``intf("%.2f", (double)9.999);'';
  300.              * if the first char isn't NULL, it did.
  301.              */
  302.             *buf = (char)NULL;
  303.             size = cvt(_double, (int)prec, (int)flags, &softsign,
  304.                    *fmt, buf, buf + (int)sizeof(buf)); 
  305.             if (softsign)
  306.                 sign = '-';
  307.             t = *buf ? buf : buf + 1;
  308.             goto pforw;
  309. #endif /* __FLOATS__ */
  310.         case 'n':
  311.             if (flags & LONGINT)
  312.                 *va_arg(argp, long *) = cnt;
  313.             else if (flags & SHORTINT)
  314.                 *va_arg(argp, short *) = cnt;
  315.             else
  316.                 *va_arg(argp, int *) = cnt;
  317.             break;
  318.         case 'O':